package net.kelissa.jenetic.impl.organism;

import java.util.List;

import net.kelissa.jenetic.Conceiver;
import net.kelissa.jenetic.Fitner;
import net.kelissa.jenetic.Gene;
import net.kelissa.jenetic.Mutator;
import net.kelissa.jenetic.Organism;
import net.kelissa.jenetic.RandomUtil;
import net.kelissa.jenetic.impl.conceiver.ConceiverDelegateGene;
import net.kelissa.jenetic.impl.mutator.MutatorBase;

public class OrganismBase implements Organism
{

  protected int age = 0;

  protected List<Gene> genes;

  //TODO i nomi non vanno
  protected Fitner genome;

  protected Mutator mutator;

  protected Conceiver conceiver;

  public OrganismBase(List<Gene> genes, Fitner genome)
  {
    this.genes = genes;
    this.genome = genome;
    this.mutator = new MutatorBase();
    this.conceiver = new ConceiverDelegateGene();
  }


  /**
   * mutate gene by gene
   */
  @Override
  public void mutate()
  {
    this.mutator.mutate(this.genes);
  }

  /**
   * Only clone genes
   */
  @Override
  public Organism clone()
  {

    List<Gene> newGenes = RandomUtil.clone(this.genes);

    Organism clone = new OrganismBase(newGenes, this.genome);

    clone.setAge(this.age);
    clone.setConceiver(this.conceiver);
    clone.setMutator(this.mutator);
    return clone;
  }

  /**
   * conceive gene by gene
   */
  @Override
  public Organism conceive(Organism other)
  {
    Organism newOrganism = this.clone();
    newOrganism.setAge(0);
    List<Gene> newGenes = this.conceiver.conceive(this.genes, other.getGenes());
    newOrganism.setGenes(newGenes);
    newOrganism.mutate();
    return newOrganism;
  }

  @Override
  public double fitness()
  {
    return this.genome.fitness(this.genes);
  }


  @Override
  public void age()
  {
    this.age += 1;
  }

  /**
   * inverse sort, greater fitness is best
   */
  @Override
  public int compare(Organism one, Organism other)
  {
    return new Double(other.fitness()).compareTo(one.fitness());
  }

  // -----------------------------------------
  @Override
  public int getAge()
  {
    return this.age;
  }

  @Override
  public void setAge(int age)
  {
    this.age = age;
  }

  @Override
  public List<Gene> getGenes()
  {
    return genes;
  }

  @Override
  public void setGenes(List<Gene> genes)
  {
    this.genes = genes;
  }

  @Override
  public Fitner getGenome()
  {
    return genome;
  }

  @Override
  public void setGenome(Fitner genome)
  {
    this.genome = genome;
  }

  @Override
  public Mutator getMutator()
  {
    return mutator;
  }

  @Override
  public void setMutator(Mutator mutator)
  {
    this.mutator = mutator;
  }

  @Override
  public Conceiver getConceiver()
  {
    return conceiver;
  }

  @Override
  public void setConceiver(Conceiver conceiver)
  {
    this.conceiver = conceiver;
  }


}